﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Text.RegularExpressions;

namespace Obra.Test
{
    /// <summary>
    /// An HTTP server used for unit testing.
    /// </summary>
    /// <remarks>
    /// <para>
    /// These are the facts.
    ///   1. Caller adds a list of content provider.
    ///   2. Content is provided based on the provider matching a URI request.
    ///     a. The provider is expected to provide a match for all possible URI's
    ///        to be processed.
    ///     b. 
    ///   2. The request is processed asynchronously.
    ///   3. The data returned is specified at the time of construction.
    ///   4. HTTP headers are hard-coded.
    ///     a. Content-Type: text/xml
    /// </para>
    /// <para>
    /// This code was inspired by the WCF REST toolkit code from Microsoft.
    /// </para>
    /// </remarks>
    class HttpServerMatchedContent :
        HttpServer
    {
        private readonly List<IMatchedContent> matchedContents =
            new List<IMatchedContent>();

        /// <summary>
        /// c-tor
        /// </summary>
        public HttpServerMatchedContent(
            Uri address)
            : base(address)
        {
        }

        /// <summary>
        /// List of content providers. 
        /// </summary>
        public List<IMatchedContent> MatchedContents
        {
            get { return this.matchedContents; }
        }

        /// <summary>
        /// If no provider matches the specified URI, this provider's
        /// data are used.
        /// </summary>
        public IMatchedContent DefaultMatchContent
        {
            get;
            set;
        }

        protected override void OnContextAvailable(
            IAsyncResult asyncResult)
        {
            HttpServerMatchedContent httpServer = 
                (HttpServerMatchedContent)asyncResult.AsyncState;

            try
            {
                asyncResult.AsyncWaitHandle.WaitOne();
                HttpListenerContext context = httpServer.HttpListener.EndGetContext(
                    asyncResult);

                HttpListenerRequest request = context.Request;
                HttpListenerResponse response = context.Response;

                IMatchedContent content = this.MatchedContents.SingleOrDefault(x => x.IsMatch(request.Url)) ??
                    this.DefaultMatchContent;

                content.Requests.Add(request);

                byte[] buffer = content.GetContent();

                response.Headers.Add("Content-Type: text/xml");

                response.ContentLength64 = buffer.Length;
                response.OutputStream.Write(buffer, 0, buffer.Length);
                response.Close();
            }
            catch (Exception e)
            {
                System.Console.WriteLine(e.ToString());
            }
            finally
            {
                try
                {
                    httpServer.HttpListener.BeginGetContext(
                        this.OnContextAvailable,
                        httpServer);
                }
                catch (Exception)
                {
                    // Discard, probably shutting down the server.
                }
            }
        }
    }
}
